
package com.scs.application.modules.base.service.impl;

import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.scs.application.consts.RoleConsts;
import com.scs.application.consts.SerialRuleConsts;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.model.ImportResult;
import com.scs.application.core.serial.SerialUtils;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.thread.BatchSaveTask;
import com.scs.application.core.thread.DefaultSaveHandler;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.dto.ExcelHospitalSupplierDTO;
import com.scs.application.modules.base.dto.HospitalSupplierDTO;
import com.scs.application.modules.base.entity.*;
import com.scs.application.modules.base.mapper.HospitalSupplierMapper;
import com.scs.application.modules.base.request.HospitalSupplierQueryRequest;
import com.scs.application.modules.base.request.HospitalSupplierRequest;
import com.scs.application.modules.base.service.*;
import com.scs.application.modules.base.vo.ExcelHospitalSupplierVO;
import com.scs.application.modules.base.vo.HospitalSupplierVO;
import com.scs.application.modules.upms.entity.Office;
import com.scs.application.modules.upms.entity.User;
import com.scs.application.modules.upms.service.OfficeService;
import com.scs.application.modules.upms.service.UserService;
import com.scs.application.modules.upms.vo.UserVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;

import static com.scs.application.core.serial.SerialUtils.batchGenerateCode;

/**
 * HospitalSupplier service 实现
 *
 */
@Slf4j
@Service
@AllArgsConstructor
public class HospitalSupplierServiceImpl extends BaseServiceImpl<HospitalSupplierMapper, HospitalSupplier> implements HospitalSupplierService {


    private final SupplierService supplierService;

    private final HospitalService hospitalService;

    private final HospitalMaterialService hospitalMaterialService;

    private final OfficeService officeService;

    private final UserService userService;

    @Override
    public List<HospitalSupplier> list(HospitalSupplierQueryRequest request) {
        request.setHospitalId(UserUtils.isHospital() ? UserUtils.getHospitalId() : null);
        request.setSupplierId(UserUtils.isSupplier() ? UserUtils.getSupplierId() : null);
        return this.baseMapper.list(request);
        /*List<HospitalSupplier> list = this.list(Wrappers.<HospitalSupplier>query()
                .eq(StringUtils.isNotBlank(request.getHospitalId()), "hospital_id", request.getHospitalId())
                .eq(StringUtils.isNotBlank(request.getSupplierId()), "supplier_id", request.getSupplierId())
                .eq("inactive", HospitalSupplier.ENABLE)
                .orderByDesc("gmt_modified")
        );

        return list;*/
    }

    @Override
    public IPage<HospitalSupplier> page(HospitalSupplierQueryRequest request) {
        request.setHospitalId(UserUtils.isHospital() ? UserUtils.getHospitalId() : null);
        request.setSupplierId(UserUtils.isSupplier() ? UserUtils.getSupplierId() : null);
        return this.baseMapper.page(request.getPage(), request);

    }

    @Override
    public List<HospitalSupplierVO> listVO(HospitalSupplierRequest request) {
        String hospitalId = UserUtils.getHospitalId();
//        String hospitalId = "1207843304381161473";
        return this.baseMapper.listVO(new HospitalSupplierQueryRequest()
                .setHospitalId(hospitalId)
                .setCode(request.getCode())
                .setBeginDate(request.getBeginDate()));

    }

    @Override
    public List<HospitalSupplierVO> listBySupplier(HospitalSupplierRequest request) {
        String supplierId = UserUtils.getSupplierId();
//        String supplierId = "1244510289349677057";
        return this.baseMapper.listBySupplier(new HospitalSupplierQueryRequest()
                .setSupplierId(supplierId)
                .setHospitalCode(request.getHospitalCode())
                .setBeginDate(request.getBeginDate())
        );
    }

    @Override
    public List<HospitalSupplierVO> listByHospital(HospitalSupplierRequest request) {
        return this.baseMapper.listByHospital(new HospitalSupplierQueryRequest().setHospitalId(request.getHospitalId())
                .setInactive(request.getInactive())
        );
    }


    @Override
    public void enable(String id) {
        HospitalSupplier hs = this.getById(id);
        if (hs == null) {
            return;
        }
        //当前状态是否是停用状态
        if (hs.getInactive() != HospitalSupplier.DISABLE) {
            return;
        }

        //修改状态为正常状态
        HospitalSupplier hospitalSupplier = new HospitalSupplier();
        hospitalSupplier.setInactive(HospitalSupplier.ENABLE).setId(hs.getId());
        //修改医院耗材表，供应商对应耗材启用
        List<HospitalMaterial> list = hospitalMaterialService.list(Wrappers.<HospitalMaterial>query().eq("hospital_id", UserUtils.getHospitalId())
                .eq("supplier_id", hs.getSupplierId())
        );
        if (list.size() > 0) {
            list.forEach(o -> o.setInactive(HospitalMaterial.ACTIVATE));
            hospitalMaterialService.updateBatchById(list);
        }
        this.updateById(hospitalSupplier);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void disable(String id) {
        HospitalSupplier hs = this.getById(id);
        if (hs == null) {
            return;
        }
        //当前状态是否是正常状态
        if (hs.getInactive() != HospitalSupplier.ENABLE) {
            return;
        }

        //修改状态为停用状态
        HospitalSupplier hospitalSupplier = new HospitalSupplier();
        hospitalSupplier.setInactive(HospitalSupplier.DISABLE).setId(hs.getId());
        //修改医院耗材表，供应商对应耗材启用
        List<HospitalMaterial> list = hospitalMaterialService.list(Wrappers.<HospitalMaterial>query().eq("hospital_id", UserUtils.getHospitalId())
                .eq("supplier_id", hs.getSupplierId())
        );
        if (list.size() > 0) {
            list.forEach(o -> o.setInactive(HospitalMaterial.DEACTIVATE));
            hospitalMaterialService.updateBatchById(list);
        }
        this.updateById(hospitalSupplier);
    }

    /**
     * 根据供货商名称查询供货商id
     */
    @Override
    public HospitalSupplier findBySupplierName(String supplierName, String hospitalId) {
        List<HospitalSupplier> list = this.baseMapper.findBySupplierName(supplierName, hospitalId);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public void allActive() {
        this.update(Wrappers.<HospitalSupplier>update()
                .eq("hospital_id", UserUtils.getHospitalId())
                .set("inactive", HospitalSupplier.ENABLE)
        );
    }

    @Override
    public void allInactive() {
        this.update(Wrappers.<HospitalSupplier>update()
                .eq("hospital_id", UserUtils.getHospitalId())
                .set("inactive", HospitalSupplier.DISABLE)
        );
    }


    @Override
    public List<ExcelHospitalSupplierVO> listExcel(HospitalSupplierQueryRequest request) {
        return this.baseMapper.listExcel(request);
    }

    /**
     * 第三方接口批量保存修改医院供应商信息
     * 没有传递供应商编码的，由系统自动生成，否则取现成的
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> batchSave(List<HospitalSupplierDTO> dtos) {
        log.info("==============医院供应商批量保存开始=================");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        int insertSize = 0;
        int updateSize = 0;
        String hospitalId = UserUtils.getHospitalId();
        String hospitalName = UserUtils.getHospital().getName();
        /** 批量生成供应商编码 */
        int grCodecount = (int) dtos.stream().filter(o -> StringUtils.isBlank(o.getCode())).count();
        List<String> codes = Lists.newArrayListWithExpectedSize(grCodecount);
        if (grCodecount > 0) {
            codes = batchGenerateCode(SerialRuleConsts.BASE_SUPPLIER_CODE, grCodecount);
        }
        int codeIndex = 0;
        ArrayList<String> returnCodeList = Lists.newArrayListWithExpectedSize(grCodecount);
        //查询所有供应商
        List<Supplier> supplierList = supplierService.list(
                Wrappers.<Supplier>query().select("id,code,name")
        );
        Map<String, Supplier> supplierMap = supplierList.stream().collect(Collectors.toMap(o -> o.getId(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条供应商数据", supplierMap.size());

        List<String> supplierIdAddList  = new ArrayList<>();
        for (HospitalSupplierDTO dto : dtos) {
            Supplier supplier = new Supplier();
            BeanUtils.copyProperties(dto, supplier);
            String code = supplier.getCode();
            // 是否新供应商
            boolean isNewHs = supplierMap.get(code) == null;
            supplier.setCode(StringUtils.isBlank(code) ? codes.get(codeIndex++) : code);
            if (StringUtils.isBlank(supplier.getCompanyCode())) {
                supplier.setCompanyCode(supplier.getCode());
            }
            if (StringUtils.isBlank(dto.getLoginKey())) {
                supplier.setLoginKey(supplier.getCode());
            }
            //判断供应商名称是否存在
            Supplier s = supplierService.getOne(Wrappers.<Supplier>query().eq("name", supplier.getName()));
            if (s != null) {
                BeanUtils.copyProperties(dto, s);
                supplier.setId(s.getId());
                returnCodeList.add(s.getId());
                supplierService.updateById(s);

                // 更新用户禁用状态
                Office officeFind = officeService.getOne(Wrappers.<Office>query().eq("name", s.getName()));
                if (officeFind != null) {
                    //是否有效 1：正常 0：停用
                    userService.update(Wrappers.<User>update().set("inactive",!dto.getFlagDisabled()).eq("office_id", officeFind.getId()));
                }
            } else {
                //添加供应商
                // 当新增供应商时添加机构、用户
                Office office = new Office();
                office.setCode(supplier.getCompanyCode()).setType(Office.TYPE_SUPPLIER)
                        .setName(supplier.getName());
                officeService.save(office);
                if (office == null || StringUtils.isBlank(office.getId())) {
                    throw new BusinessException("机构添加失败");
                }
                supplier.setOfficeId(office.getId());

                UserVO userVO = new UserVO();
                userVO.setOfficeId(office.getId())
                        .setLoginKey(supplier.getLoginKey())
                        .setNickname(supplier.getName())
                        .setEmail(supplier.getEmail())
                        .setMobile(supplier.getMobile())
                        .setRoleCodes(Lists.newArrayList(RoleConsts.SUPPLIER_MANAGER))
                        .setRemark("供应商" + supplier.getName() + "主账号");
                User user = userService.addUser(userVO);

                if (user == null || StringUtils.isBlank(user.getId())) {
                    throw new BusinessException("主用户" + supplier.getLoginKey() + "可能已存在，添加失败");
                }
                supplierService.save(supplier);
                insertSize++;
                returnCodeList.add(supplier.getId());
            }

            //如果供应的已经存在 医院供应商是否建立关系
            List<HospitalSupplier> hs = this.baseMapper.selectList(Wrappers.<HospitalSupplier>query().eq("hospital_id", hospitalId)
                    .eq("supplier_id", supplier.getId()));
            if (ObjectUtil.length(hs) != 0) {
                log.info(supplier.getName() + "与" + hospitalName + "已建立关系");
                continue;
            }
            //建立关系
//            HospitalSupplier hospitalSupplier = new HospitalSupplier();
//            hospitalSupplier.setHospitalId(hospitalId).setSupplierId(supplier.getId()).setInactive(dto.getInactive());
//            hsList.add(hospitalSupplier);
            supplierIdAddList.add(supplier.getId());
        }
        if (ObjectUtil.length(supplierIdAddList) != 0) {
            List<SupplierApplicant> applicantList = Lists.newArrayList();
            SupplierApplicant supplierApplicant;
            int index = 0;
            Date now = DateUtils.now();
            List<String> codeList = SerialUtils.batchGenerateCode(SerialRuleConsts.BASE_SUPPLIER_APPLICANT_CODE, SerialOwnerUtils.getHospitalOwner(hospitalId),supplierIdAddList.size());
            for(String supplierId : supplierIdAddList) {
                supplierApplicant = new SupplierApplicant();
                supplierApplicant.setHospitalId(hospitalId).setSupplierId(supplierId);
                supplierApplicant.setCode(codeList.get(index)).setRemark("物资系统推送自动创建");
                supplierApplicant.setGmtAudited(now).setAuditor("系统").setAuditedRemark("自动审核通过").setStatus(SupplierApplicant.STATUS_PASSED);
                index++;
                applicantList.add(supplierApplicant);
            }

            SpringUtils.getBean(SupplierApplicantServiceImpl.class).saveBatchWithPass(applicantList);
        }
        log.info("新增{}条供应商数据", insertSize);
        return returnCodeList;
    }

    @Override
    public HospitalSupplierVO findBySupplierIdAndHospitalId(String supplierId, String hospitalId) {
        HospitalSupplier hospitalSupplier = this.getOne(
                Wrappers.<HospitalSupplier>query().eq("supplier_id", supplierId).eq("hospital_id", hospitalId)
                        .last("limit 1")
        );
        if (hospitalSupplier == null) {
            return null;
        }
        HospitalSupplierVO vo = new HospitalSupplierVO();
        BeanUtils.copyProperties(hospitalSupplier, vo);
        return vo;
    }

    @Override
    public ImportResult excelImport(MultipartFile file) {
        return excelImport(file, null);
    }

    @Override
    protected ExcelImportResult doExcelImport(MultipartFile multipartFile, Map<String, Object> params) throws Exception {
        ImportParams importParams = PoiUtils.getDefaultImportParams();

        long currentTimeMillis = System.currentTimeMillis();
        ExcelImportResult importResult = PoiUtils.importExcelMore(multipartFile.getInputStream(), ExcelHospitalSupplierDTO.class, importParams);
        log.info("文件加载耗时：{}", DateUtils.formatTime(System.currentTimeMillis() - currentTimeMillis));

        List<ExcelHospitalSupplierDTO> dtoList = Lists.newArrayList(importResult.getList());

        List<String> hospitalNameList = dtoList.parallelStream().map(o -> o.getHospitalName()).distinct().collect(Collectors.toList());
        if (hospitalNameList.isEmpty()) {
            throw new BusinessException("请确认医院名称是否已存在");
        }

        //查询出所有医院
        List<Hospital> hospitalList = hospitalService.list(Wrappers.<Hospital>query().select("id,name").in("name", hospitalNameList));
        Map<String, Hospital> hospitalMap = hospitalList.stream().collect(Collectors.toMap(o -> o.getName(), o -> o, (o1, o2) -> o1));

        List<String> hospitalIdList = hospitalList.stream().map(o -> o.getId()).collect(Collectors.toList());
        if (hospitalIdList.isEmpty()) {
            BusinessException.throwError("请确认医院名称是否已存在，医院名称{}",StringUtils.join(hospitalNameList,","));
        }

        List<HospitalSupplier> hsList = this.list(Wrappers.<HospitalSupplier>query()
                .select("id,hospital_id,supplier_id")
                .in("hospital_id", hospitalIdList)
        );
        Map<String, HospitalSupplier> hospitalSupplierMap = hsList.stream().collect(Collectors.toMap(o -> o.getHospitalId() + o.getSupplierId(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条医院供应商数据", hospitalSupplierMap.size());

        // 查询出所有供应商
        List<Supplier> supplierList = supplierService.list(
                Wrappers.<Supplier>query()
                        .select("id,name")
        );
        Map<String, Supplier> supplierMap = supplierList.stream().collect(Collectors.toMap(o -> o.getName(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条供应商数据", supplierMap.size());


        boolean isHospital = UserUtils.isHospital();

        ConcurrentLinkedQueue<HospitalSupplier> result = new ConcurrentLinkedQueue();

        DefaultSaveHandler<ExcelHospitalSupplierDTO> saveHandler = new DefaultSaveHandler<ExcelHospitalSupplierDTO>() {
            @Override
            public void doSave(int currentIndex, ExcelHospitalSupplierDTO entity) throws BusinessException {

                HospitalSupplier hs = new HospitalSupplier();
                BeanUtils.copyProperties(entity, hs);
                Hospital hospital = hospitalMap.get(entity.getHospitalName());
                if (hospital == null) {
                    importResult.getList().remove(entity);
                    entity.setErrorMsg(String.format("医院不存在"));
                    importResult.getFailList().add(entity);
                    log.warn("第{}行医院不存在，请先确认数据是否正确；医院名称：{}", entity.getRowNum(), entity.getHospitalName());
                    return;
                }
                hs.setHospitalId(hospital.getId());

                Supplier supplier = supplierMap.get(entity.getSupplierName());
//                Supplier supplier = supplierService.getOne(Wrappers.<Supplier>query().select("id,name").eq("name", entity.getSupplierName()).last("limit 1"));
                if (supplier == null) {
                    importResult.getList().remove(entity);
                    entity.setErrorMsg(String.format("供应商不存在"));
                    importResult.getFailList().add(entity);
                    log.warn("第{}行供应商不存在，请先确认数据是否正确；供应商名称：{}", entity.getRowNum(), entity.getSupplierName());
                    return;
                }

                hs.setSupplierId(supplier.getId());

                HospitalSupplier hospitalSupplier = hospitalSupplierMap.get(hs.getHospitalId() + hs.getSupplierId());
                if (hospitalSupplier != null) {
                    return;
                }
                result.add(hs);
            }
        };
        BatchSaveTask<ExcelHospitalSupplierDTO> task = new BatchSaveTask(saveHandler, dtoList);

        this.forkJoinPool.invoke(task);


        List<HospitalSupplier> updateHospitalSuppliers = result.stream().filter(o -> StringUtils.isNotBlank(o.getId())).collect(Collectors.toList());
        List<HospitalSupplier> insertHospitalSuppliers = result.stream().filter(o -> StringUtils.isBlank(o.getId())).collect(Collectors.toList());
        if (!updateHospitalSuppliers.isEmpty()) {
            this.updateBatchById(updateHospitalSuppliers);
        }
        if (!insertHospitalSuppliers.isEmpty()) {
            // this.saveBatch(insertHospitalSuppliers);
            this.baseMapper.insertBatchSomeColumn(Lists.newArrayList(insertHospitalSuppliers));
        }
        return importResult;
    }
}
